package com.agnes.network;

import android.content.Context;
import android.text.TextUtils;

import com.agnes.network.callback.RespCallback;
import com.agnes.network.interceptor.RequestInterceptor;
import com.agnes.network.observer.DataListObserver;
import com.agnes.network.observer.DataObserver;
import com.agnes.network.observer.JAObserver;
import com.agnes.network.observer.JOObserver;
import com.agnes.network.observer.StrObserver;
import com.agnes.network.security.SSLUtils;
import com.agnes.network.security.TrustAllHostnameVerifier;
import com.agnes.network.util.JsonUtils;
import com.agnes.network.util.Utils;
import com.orhanobut.logger.Logger;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;
import org.json.JSONArray;
import org.json.JSONObject;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Desc:   说明缓存策略：OkHttp建议在不是Get请求的响应体不要缓存，因为如果缓存的话会提高它的复杂性而且好处不大。
 * 没看到这段话之前。郁闷了很久为什么Post请求缓存生成不了，而且会报一个错 504 Unsatisfiable Request (only-if-cached)
 * post的缓存需要结合数据库
 * Creator ling
 * Date:   2017/9/8 0008 15:12
 */

public class HttpManager {
    private String TAG = this.getClass().getName();
    private static volatile HttpManager mInstance;
    private static ApiService apiService;
    private static OkHttpClient ok;
    private static CompositeDisposable sCompositeDisposable;
    private String baseUrl;

    //超时时间 10s
    private static final int TIMEOUT = 1000 * 10;

    public static HttpManager getInstance() {
        if (mInstance == null) {
            synchronized (HttpManager.class) {
                if (mInstance == null) {
                    mInstance = new HttpManager();
                }
            }
        }
        return mInstance;
    }

    public void init(Context context, String baseUrl,String versionName) {
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient okHttpClient =
            new OkHttpClient.Builder().sslSocketFactory(SSLUtils.getDefaultSocketFactory())
                .hostnameVerifier(new TrustAllHostnameVerifier())
                .readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                .addInterceptor(new RequestInterceptor(versionName))
                .addInterceptor(loggingInterceptor)
                .build();
        Retrofit retrofit = new Retrofit.Builder().client(okHttpClient).baseUrl(baseUrl)
            // 增加返回值为String的支持
            .addConverterFactory(ScalarsConverterFactory.create())
            // 增加返回值为Gson的支持(以实体类返回)
            .addConverterFactory(GsonConverterFactory.create())
            // 增加返回值为Observable<T>的支持
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();

        this.baseUrl = baseUrl;

        apiService = retrofit.create(ApiService.class);
        sCompositeDisposable = new CompositeDisposable();
    }

    /**
     * post 请求，回调的泛型为 JSONObject(data:{})
     *
     * @param path         接口相对路径
     * @param params       参数
     * @param respCallback 回调
     */
    public void postForJO(String path, Map<String, Object> params,
                          RespCallback<JSONObject> respCallback) {
        JOObserver observer = new JOObserver(respCallback, sCompositeDisposable);
        post(path, params).subscribe(observer);
    }

    /**
     * post 请求，回调的泛型为 Entity(data:{},解析成 对象)
     * 注意: 实体类需要序列化
     *
     * @param path         接口相对路径
     * @param params       参数
     * @param respCallback 回调
     */
    public <T> void postForEntity(String path, Map<String, Object> params,
                                  RespCallback<T> respCallback) {
        DataObserver<T> observer = new DataObserver<>(respCallback, sCompositeDisposable);
        post(path, params).subscribe(observer);
    }

    /**
     * post 请求，回调的泛型为 JSONArray(data:[])
     *
     * @param path         接口相对路径
     * @param params       参数
     * @param respCallback 回调
     */
    public void postForJA(String path, Map<String, Object> params,
                          RespCallback<JSONArray> respCallback) {
        JAObserver observer = new JAObserver(respCallback, sCompositeDisposable);
        post(path, params).subscribe(observer);
    }

    /**
     * post 请求，回调的泛型为 List<Entity> (data:[],解析成 对象列表)
     * 注意: 实体类需要序列化
     *
     * @param path         接口相对路径
     * @param params       参数
     * @param respCallback 回调
     */
    public <T> void postForEntityList(String path, Map<String, Object> params,
                                      RespCallback<T> respCallback) {
        DataListObserver<T> observer = new DataListObserver<>(respCallback, sCompositeDisposable);
        post(path, params).subscribe(observer);
    }

    /**
     * post 请求，回调的泛型为 String(data:"")
     *
     * @param path         接口相对路径
     * @param params       参数
     * @param respCallback 回调
     */
    public void postForStr(String path, Map<String, Object> params,
                           RespCallback<String> respCallback) {

        StrObserver observer = new StrObserver(respCallback, sCompositeDisposable);
        post(path, params).subscribe(observer);
    }

    private Observable<String> post(String path, Map<String, Object> params) {
        Logger.e("api = " + baseUrl + path);
        String headerToken = "";
        if (params != null && !params.isEmpty() && params.containsKey(Const.LOGIN_TOKEN)) {
            headerToken = (String) params.get(Const.LOGIN_TOKEN);
            // 参数里面移除params
            params.remove(Const.LOGIN_TOKEN);
        }

        Logger.e("header = " + headerToken);
        String json = JsonUtils.toJson(params);
        Logger.e("jsonParam = " + json);

        RequestBody requestBody =
            RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);

        Observable<String> observable;
        if (TextUtils.isEmpty(headerToken)) {
            observable = apiService.post(path, requestBody);
        } else {
            observable = apiService.post(headerToken, path, requestBody);
        }

        return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * post 请求，回调的泛型为 JSONObject
     *
     * @param path         接口相对路径
     * @param params       参数
     * @param respCallback 回调
     */
    public void getForJO(String path, Map<String, Object> params,
                         RespCallback<JSONObject> respCallback) {
        JOObserver observer = new JOObserver(respCallback, sCompositeDisposable);
        get(path, params).subscribe(observer);
    }

    private Observable<String> get(String path, Map<String, Object> params) {
        Logger.e("api =>> " + baseUrl + path);
        Logger.e("param ==>> " + Utils.covertForm(params));

        String headerToken = "";
        if (params != null && !params.isEmpty() && params.containsKey(Const.LOGIN_TOKEN)) {
            headerToken = (String) params.get(Const.LOGIN_TOKEN);
            // 参数里面移除params
            params.remove(Const.LOGIN_TOKEN);
        }

        Observable<String> observable = apiService.get(headerToken, path, params);

        return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 页面销毁时，切断网络请求，避免请求后更新UI发生崩溃
     */
    public void removeRequst() {
        sCompositeDisposable.clear();
    }
}
